#ifndef A3E421D8_5A6F_4F84_8150_C872CD01D837
#define A3E421D8_5A6F_4F84_8150_C872CD01D837

// 书上是这样说的, 创建一个电视机类和一个遥控器类
// 遥控器能够改变电视机的状态, 遥控器应当为电视类的友元类

// 创建这样的一个友元类, 使用下面的语句
// friend class Remote;

class Tv
{
public:
    friend class Remote; // Remote can access Tv private parts
    enum{Off,On};
    enum{MinVal,MaxVal = 20};
    enum{Antenna,Cable};
    enum{TV,DVD};

    Tv(int s = Off, int mc = 125) : state(s), volume(5),
                                    maxchannel(mc), channel(2), mode(Cable), input(TV) {}
    void onoff() { state = (state == On) ? Off : On; }
    bool ison() const { return state == On; }
    bool volup();
    bool voldown();
    void chanup();
    void chandown();
    void set_mode() { mode = (mode == Antenna) ? Cable : Antenna; }
    void set_input() { input = (input == TV) ? DVD : TV; }
    void settings() const; // display all settings
private:
    int state;      // on or off
    int volume;     // assumed to be digitized
    int maxchannel; // maximum number of channels
    int channel;    // current channel setting
    int mode;       // broadcast or cable
    int input;      // TV or DVD
};

class Remote
{
private:
    int mode; // controls TV or DVD
public:
    Remote(int m = Tv::TV) : mode(m) {}
    bool volup(Tv &t) { return t.volup(); }
    bool voldown(Tv &t) { return t.voldown(); }
    void onoff(Tv &t) { t.onoff(); }
    void chanup(Tv &t) { t.chanup(); }
    void chandown(Tv &t) { t.chandown(); }
    void set_chan(Tv &t, int c) { t.channel = c; }
    void set_mode(Tv &t) { t.set_mode(); }
    void set_input(Tv &t) { t.set_input(); }
};

// 友元成员函数
// 其他的函数因为有对应的getter和setter,只有这一个Remote::set_chan()直接访问了Tv中的成员
// 确实可以让特定的类成员成为另一个类的友元, 但是有一些麻烦, 必须小心声明的顺序
// 让Remote::set_chan()函数单独成为函数的友元的方法是,在Tv类声明中将其声明成为友元
// class Tv{
//     friend void Remote::set_chan(Tv &t,int c);
//     // ......
// }

// 在这个时候必须让Tv类知道set_chan()是Remote中的方法
// 所以应当在Tv类之前声明Remote类;
// 又因为Remote中需要传递Tv类参数, Tv应当在Remote之前.....
// 这里引出前向声明(forward declaration),就像下面的这样:

// class Tv;
// class Remote {
    // Remote(int m = Tv::TV) : mode(m) {}
    // ......
// }
// class Tv{
    // Tv(int s = Off, int mc = 125) : state(s), volume(5),
    //     maxchannel(mc), channel(2), mode(Cable), input(TV) {}

// }

// 需要记住的一点是: 对于Remote对象使用的Tv方法,其原型可以在Remote类声明之前声明,
// 但是必须在Remote类声明后定义, 以便编译器有足够的信息来编译该方法

// 有些时候函数需要友元访问两个类的私有数据,从逻辑上看,这个函数应当是每一类的友元函数, 但是这样是不可能的!
// 但是有些时候将函数作为两个类的友元函数更加合理.
class Analyzer;

class Probe {
    friend void sync(Analyzer & a, const Probe & p);
    friend void sync(Probe &p, const Analyzer &a );
    //.......
};

class Analyzer {
    friend void sync(Analyzer & a, const Probe & p);
    friend void sync(Probe & p, const Analyzer & a);

};

inline void sync(Analyzer &a, const Probe &p)
{
    //......
}

inline void sync(const Probe &p, Analyzer &a)
{
    //......
}
#endif /* A3E421D8_5A6F_4F84_8150_C872CD01D837 */
